package com.tanhua.server.service;
import com.tanhua.domain.db.User;
import com.tanhua.domain.mongo.Visitors;
import com.tanhua.domain.vo.CommentVo;
import com.tanhua.domain.vo.VisitorsVo;
import com.tanhua.dubbo.api.UserApi;
import com.tanhua.dubbo.api.mongo.VisitorsApi;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.bson.types.ObjectId;

import com.tanhua.commons.template.OssTemplate;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.mongo.Comment;
import com.tanhua.domain.mongo.Publish;
import com.tanhua.domain.vo.MovementsVo;
import com.tanhua.domain.vo.PageResult;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.mongo.CommentApi;
import com.tanhua.dubbo.api.mongo.PublishApi;
import com.tanhua.server.interceptor.UserHolder;
import com.tanhua.server.utils.RelativeDateFormat;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Service
public class MovementsService {
    @Reference
    private PublishApi publishApi;
    @Reference
    private UserInfoApi userInfoApi;
    @Autowired
    private OssTemplate ossTemplate;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Reference
    private CommentApi commentApi;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 接口名称：动态-发布
     * 接口路径：POST/movements
     */
    public ResponseEntity<Object> saveMovements(
            Publish publish, MultipartFile[] imageContent) throws IOException {
            // 保存上传的图片
            List<String> medias = new ArrayList<>();
            // 处理动态中的图片，上传到阿里云OSS
            if (imageContent != null && imageContent.length>0) {
                for (MultipartFile file : imageContent) {
                    String url = ossTemplate.upload(
                            file.getOriginalFilename(), file.getInputStream());
                    medias.add(url);
                }
            }
            // 设置封装图片到publish对象中
            publish.setMedias(medias);
            // 设置用户id
            publish.setUserId(UserHolder.getUserId());
            // 发布动态，保存动态信息
            // 【设置动态id、默认状态为0】
            publish.setId(ObjectId.get());
            publish.setState(0);
            publishApi.save(publish);

            try {
                // 动态审核：发送mq消息，交给消费者工程调用华为云动态审核
                // 发送消息，消息内容：动态id
                rocketMQTemplate.convertAndSend("tanhua-publish-152",publish.getId().toString());
            } catch (MessagingException e) {
                e.printStackTrace();
            }
            return ResponseEntity.ok(null);


    }

    /**
     * 接口名称：好友动态
     * 需求分析：查询好友动态，就是刷朋友圈，查询时间线表. 登陆用户id是1，查询的表quanzi_timeline_1
     */
    public ResponseEntity<Object> queryPublishList(Integer page, Integer pagesize) {
        //1. 获取登陆用户id
        Long userId = UserHolder.getUserId();
        //2. 调用Api分页查询好友动态
        PageResult pageResult = publishApi.findByTimeLine(userId,page,pagesize);
        // 调用抽取的方法，设置返回结果
        this.setMovementsVo(pageResult);
        return ResponseEntity.ok(pageResult);
    }

    /**
     * 接口名称：推荐动态
     * 需求分析：查询登陆用户的推荐动态 db.recommend_quanzi.find({userId:1})
     */
    public ResponseEntity<Object> queryRecommendPublishList(
            Integer page, Integer pagesize) {
        //1. 获取登陆用户id
        Long userId = UserHolder.getUserId();
        //2. 根据登陆用户id，查询推荐动态
        //【推荐动态：首先从redis用户的推荐动态数据，如果没有获取到再去recommend_quanzi表获取】
        //【先从redis中获取推荐数据】
        PageResult pageResult = findAllByRecommend(page,pagesize);
        if (pageResult == null) {
            //【如果没有获取到，查询mongo默认推荐数据】
            pageResult =
                    publishApi.queryRecommendPublishList(userId, page, pagesize);
        }
        // 调用抽取的方法，封装返回结果
        this.setMovementsVo(pageResult);
        return ResponseEntity.ok(pageResult);
    }
    // 先从redis中获取推荐数据
    private PageResult findAllByRecommend(Integer page, Integer pagesize) {
        //1. 构造key
        String key = "QUANZI_PUBLISH_RECOMMEND_" + UserHolder.getUserId();
        //2. 获取redis中的推荐动态id（pid）  value = 100092,82,22,20,33,10020,36,36,38,31
        String values = redisTemplate.opsForValue().get(key);
        if(StringUtils.isEmpty(values)) {
            return null;
        }
        //3. 分割字符串
        String[] pids = values.split(",");
        int counts = pids.length;

        //4. 查询的开始行 (举例：每页显示3条)
        int startIndex = (page - 1) * pagesize;
        //5. 判断：查询的起始行小于总行数
        if(startIndex < pids.length) { //起始条数小于数据总数
            int endIndex = startIndex + pagesize - 1;
            if (endIndex >= pids.length) {
                endIndex = pids.length - 1;
            }
            //5. 遍历：获取pid集合
            List<Long> pidList = new ArrayList<>();
            for (int i = startIndex; i <= endIndex; i++) {
                pidList.add(Long.valueOf(pids[i]));
            }
            //6. 把pid集合作为条件查询
            List<Publish> list = publishApi.findByPids(pidList);
            return new PageResult(page, pagesize, counts, list);
        }
        return null;
    }

    // 抽取的公用方法：把pageResult中的动态集合，转换为movomentsVo集合
    public void setMovementsVo(PageResult pageResult) {
        //3. 获取返回的动态集合
        List<Publish> publishList = (List<Publish>) pageResult.getItems();
        //4. 定义接口返回的vo集合
        List<MovementsVo> voList = new ArrayList<>();
        //4.1 封装数据
        if (!CollectionUtils.isEmpty(publishList)) {
            for (Publish publish : publishList) {
                // 4.2创建对象
                MovementsVo vo = new MovementsVo();
                // 数据封装 publish--->vo
                this.convertPublishToMovementsVo(publish,vo);
                // 添加到结合
                voList.add(vo);
            }
        }
        //5. 返回
        pageResult.setItems(voList);
    }
    // 把publish--->movementsVo对象
    public void convertPublishToMovementsVo(Publish publish,MovementsVo vo){
        // 4.3 封装对象
        // 根据用户id查询
        UserInfo userInfo = userInfoApi.findById(publish.getUserId());
        if (userInfo != null) {
            BeanUtils.copyProperties(userInfo,vo);
            if (userInfo.getTags() != null) {
                vo.setTags(userInfo.getTags().split(","));
            }
        }
        // 对象拷贝：publish--->vo
        BeanUtils.copyProperties(publish,vo);
        // 设置动态id
        vo.setId(publish.getId().toString());
        // 设置动态图片： 从publish中获取的是List集合，需要转换为vo需要的数组
        vo.setImageContent(publish.getMedias().toArray(new String[]{}));
        // 设置动态发布的时间：如 1小时之前
        vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));
        vo.setDistance("50米");
        // 点赞标记判断
        String key = "public_like_comment_"+UserHolder.getUserId()+"_"+vo.getId();
        if (redisTemplate.hasKey(key)) {
            vo.setHasLiked(1);
        } else {
            vo.setHasLiked(0);
        }
        // 喜欢标记判断
        String loveKey = "public_love_comment_"+UserHolder.getUserId()+"_"+vo.getId();;
        if (redisTemplate.hasKey(loveKey)) {
            vo.setHasLoved(1);
        } else {
            vo.setHasLoved(0);
        }
    }

    /**
     * 接口名称：用户动态 (我的动态)
     * 接口路径：GET/movements/all
     */
    public ResponseEntity<Object> queryAlbumList(int page, int pagesize, Long userId) {
        PageResult pageResult =
                publishApi.findByAlbum(userId,page,pagesize);
        setMovementsVo(pageResult);
        return ResponseEntity.ok(pageResult);
    }

    /**
     * 接口名称：动态-点赞
     * 接口路径：GET/movements/:id/like
     * 需求分析：1、往评论表插入数据；2、修改动态表点赞数量；3、返回点赞总数
     */
    public ResponseEntity<Object> likeComment(String publishId) {
        // 1. 获取登陆用户id
        Long userId = UserHolder.getUserId();
        // 2. 保存评论
        Long count = this.saveCommons(publishId, 1);

        // 记录对动态的点赞记录。作用：App显示动态时候，会点亮图标
        String key = "public_like_comment_"+userId+"_"+publishId;
        redisTemplate.opsForValue().set(key,"1");

        // 4. 返回点赞数量
        return ResponseEntity.ok(count.intValue());
    }

    /**
     * 接口名称：动态-取消点赞
     * 接口路径：GET/movements/:id/dislike
     */
    public ResponseEntity<Object> dislikeComment(String publishId) {
        // 1. 获取登陆用户id
        Long userId = UserHolder.getUserId();
        // 2. 创建Comment对象
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setCommentType(1);
        comment.setUserId(userId);
        // 3. 删除当前登陆用户点赞的标记
        Long count = commentApi.delete(comment);

        // 记录对动态的点赞记录。作用：App显示动态时候，会点亮图标
        String key = "public_like_comment_"+userId+"_"+publishId;
        redisTemplate.delete(key);

        // 4. 返回点赞数量
        return ResponseEntity.ok(count.intValue());
    }

    /**
     * 接口名称：动态-喜欢
     */
    public ResponseEntity<Object> loveComment(String publishId) {
        // 1. 获取登陆用户id
        Long userId = UserHolder.getUserId();
        // 2. 保存喜欢
        Long count = this.saveCommons(publishId,3);

        // 记录对动态的点赞记录。作用：App显示动态时候，会点亮图标
        String key = "public_love_comment_"+userId+"_"+publishId;
        redisTemplate.opsForValue().set(key,"1");

        // 4. 返回点赞数量
        return ResponseEntity.ok(count.intValue());
    }

    /**
     * 接口名称：动态-取消喜欢
     */
    public ResponseEntity<Object> unloveComment(String publishId) {
        // 1. 获取登陆用户id
        Long userId = UserHolder.getUserId();
        // 2. 创建Comment对象
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setCommentType(3);
        comment.setUserId(userId);
        // 3. 删除当前登陆用户点赞的标记
        Long count = commentApi.delete(comment);

        // 记录对动态的点赞记录。作用：App显示动态时候，会点亮图标
        String key = "public_love_comment_"+userId+"_"+publishId;
        redisTemplate.delete(key);

        // 4. 返回点赞数量
        return ResponseEntity.ok(count.intValue());
    }

    /**
     * 接口名称：单条动态
     * 接口路径：GET/movements/:id
     */
    public ResponseEntity<Object> queryMovementsById(String publishId) {
        // 根据动态id查询动态对象
        Publish publish = publishApi.findById(publishId);
        // 把publish发布动态对象转换为movementsVo对象并返回
        MovementsVo vo = new MovementsVo();
        // 数据封装 publish--->vo
        this.convertPublishToMovementsVo(publish,vo);
        return ResponseEntity.ok(vo);
    }

    /**
     * 接口名称：评论列表
     */
    public ResponseEntity<Object> queryCommentsList(
            String movementId, Integer page, Integer pagesize) {
        //1. 调用Api查询某个动态的评论列表
        PageResult pageResult = commentApi.findByPublishId(movementId,page,pagesize);
        //2. 获取分页数据
        List<Comment> list = (List<Comment>) pageResult.getItems();
        //3. 创建并封装vo集合
        List<CommentVo> voList = new ArrayList<>();
        //4. 封装voList
        if (!CollectionUtils.isEmpty(list)) {
            for (Comment comment : list) {
                // 根据用户id查询
                UserInfo userInfo = userInfoApi.findById(comment.getUserId());
                // 创建vo对象并封装
                CommentVo vo = new CommentVo();
                vo.setId(comment.getId().toString());
                if (userInfo!=null) {
                    vo.setAvatar(userInfo.getAvatar());
                    vo.setNickname(userInfo.getNickname());
                }
                vo.setContent(comment.getContent());
                vo.setCreateDate(new SimpleDateFormat("yyyy年MM月dd日 HH:mm")
                        .format(new Date(comment.getCreated())));
                vo.setLikeCount(0);
                vo.setHasLiked(0);
                // 添加到集合
                voList.add(vo);
            }
        }
        //5. 设置到分页对象、返回
        pageResult.setItems(voList);
        return ResponseEntity.ok(pageResult);
    }

    /**
     * 评论提交
     * @param movementId 动态id
     * @param content 评论内容
     * @return
     */
    public ResponseEntity<Object> saveComments(String movementId, String content) {
        //从redis中=========================================================
        //判断这个key是否存在
        if (!redisTemplate.hasKey("frozen_key_2_"+UserHolder.getUserId())) {
            //1. 创建并封装评论对象
            this.saveCommons(movementId,2,content);
            return ResponseEntity.ok(null);
        }
        //获取key的value
        String s  = redisTemplate.opsForValue().get("frozen_key_2_"+UserHolder.getUserId());
        return ResponseEntity.status(500).body(s);
    }

    /**
     * 抽取一个方法：保存点赞、喜欢、评论的通用代码
     */
    private Long saveCommons(String movementId, Integer commentType,String... content){
        // 2. 创建Comment对象
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(commentType);//1-点赞，2-评论，3-喜欢
        comment.setPubType(1);
        comment.setUserId(UserHolder.getUserId());
        comment.setCreated(System.currentTimeMillis());
        if (content!=null && content.length>0) {
            comment.setContent(content[0]);
        }
        // 3. 调用Api保存点赞记录
        Long count = commentApi.save(comment);
        return count;
    }

    @Reference
    private VisitorsApi visitorsApi;
    /**
     * 接口名称：谁看过我
     * @return
     */
    public ResponseEntity<Object> queryVisitors() {
        //1. 获取登陆用户id
        Long userId = UserHolder.getUserId();
        //2. 从redis获取上一次访问时间，如果没有获取到，说明是第一次访问
        String key = "visitor_time_" + userId;
        String time = redisTemplate.opsForValue().get(key);
        //3. 查询最近访客
        List<Visitors> visitorsList = null;
        if (StringUtils.isEmpty(time)) {
            //3.1 第一次登陆：查询最近的5个访客记录  举例时间是100
            visitorsList = visitorsApi.queryVisitors(userId,5);
        } else {
            //3.2 第二次登陆：查询最近访客 时间 > 100
            visitorsList = visitorsApi.queryVisitors(userId,Long.parseLong(time));
        }
        //4. 保存当前访问时间到redis
        redisTemplate.opsForValue().set(key,System.currentTimeMillis()+"");

        //5. 创建返回的vo集合
        List<VisitorsVo> voList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(visitorsList)) {
            for (Visitors visitors : visitorsList) {
                VisitorsVo vo = new VisitorsVo();
                // 根据访客的id查询
                UserInfo userInfo = userInfoApi.findById(visitors.getVisitorUserId());
                if (userInfo != null) {
                    BeanUtils.copyProperties(userInfo,vo);
                    if (userInfo.getTags() != null) {
                        vo.setTags(userInfo.getTags().split(","));
                    }
                }
                // 设置缘分值
                vo.setFateValue(visitors.getScore().intValue());
                // 封装好的vo添加到集合
                voList.add(vo);
            }
        }
        return ResponseEntity.ok(voList);
    }

    /**
     * 用户动态
     * @param page
     * @param pagesize
     * @param userId
     * @return
     */
    public ResponseEntity<Object> myMovements(Integer page, Integer pagesize, Long userId) {
        //调用api获取分页数据
        PageResult pageResult = publishApi.findByAlbum(userId, page, pagesize);
        setMovementsVo(pageResult);
        return ResponseEntity.ok(pageResult);
    }
}
